//------------------------------------------------------------------------------
// <copyright company="Telligent Systems">
//     Copyright (c) Telligent Systems Corporation.  All rights reserved.
// </copyright> 
//------------------------------------------------------------------------------

using System;
using System.Collections;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Xml;

namespace CommunityServer.Components
{
	/// <summary>
	/// Summary description for SiteUrlData.
	/// </summary>
	public class SiteUrlsData
	{
		public SiteUrlsData(string siteUrlsXmlFile)
		{
			_paths = new NameValueCollection();
			_reversePaths = new NameValueCollection();
			//_locations = new NameValueCollection();
			
			_tabUrls = new ArrayList();

            Initialize(siteUrlsXmlFile);
		}

		protected XmlDocument CreateDoc(string siteUrlsXmlFile)
		{
			XmlDocument doc = new XmlDocument();
			doc.Load( siteUrlsXmlFile );
			return doc;
		}



        protected void Initialize(string siteUrlsXmlFile)
        {
            string globalPath = Globals.ApplicationPath;
            if(globalPath != null)
                globalPath = globalPath.Trim();

            // Load SiteUrls from the SiteUrls.xml file
            //
            XmlDocument doc = CreateDoc(siteUrlsXmlFile);
            
            XmlNode basePaths = doc.SelectSingleNode("SiteUrls/locations");
            _locationSet =  CreateLocationSet(basePaths, globalPath);
            _locationFilter = _locationSet.Filter;


			#region SiteUrls

            XmlNode transformers = doc.SelectSingleNode("SiteUrls/transformers");
            ListDictionary transforms = CreateTransformers(transformers);

            XmlNode urls = doc.SelectSingleNode("SiteUrls/urls");
            CreateUrls(urls, transforms);

            #endregion

            CreateNavigation(doc.SelectSingleNode("SiteUrls/navigation"));
			CreateMappings(doc.SelectSingleNode("SiteUrls/mappings"), globalPath);
        }

		#region Mappings
		private void CreateMappings(XmlNode maps, string globalPath)
		{
			if(maps != null)
			{
				foreach(XmlNode map in maps.ChildNodes)
				{
					if(map != null && map.NodeType != XmlNodeType.Comment)
					{
						XmlAttribute l = map.Attributes["location"];
						XmlAttribute a = map.Attributes["path"];

						if(l != null && a != null)
						{
							string path = (globalPath + "/" + a.Value).Replace("//","/");
							ApplicationKeyMapping am = new ApplicationKeyMapping(l.Value, path);
							_mappings.Add(am);
						}
					}
				}
			}
		}
		#endregion

		#region Navigation
	    protected virtual void CreateNavigation(XmlNode nav)
	    {
	        if(nav != null)
	        {
	            foreach(XmlNode node in nav.ChildNodes)
	            {
	                if(node.NodeType != XmlNodeType.Comment)
	                {
	                    XmlAttribute name = node.Attributes["name"];

	                    XmlAttribute resourceUrl = node.Attributes["resourceUrl"];
	                    XmlAttribute resourceName = node.Attributes["resourceName"];

	                    XmlAttribute navigateUrl = node.Attributes["navigateUrl"];
	                    XmlAttribute text = node.Attributes["text"];

	                    XmlAttribute roles = node.Attributes["roles"];

	                    XmlAttribute iNavType = node.Attributes["type"];

                        XmlAttribute appType = node.Attributes["applicationType"];
                        ApplicationType at = ApplicationType.Unknown;
                        if(appType != null)
                        {
                            at = (ApplicationType)Enum.Parse(typeof(ApplicationType),appType.Value,true);
                        }

                        CSApplicationData data = ApplicationSet.Applications[at];
                        if(data != null)
                        {
                            if(!data.Enabled)
                                continue;
                        }

	                    // Set roles to "Everyone" if the attribute is null
	                    string rolesValue;
	                    if(roles == null)
	                        rolesValue = "Everyone";
	                    else
	                        rolesValue = roles.Value;

	                    string navType = null;
	                    if(iNavType != null)
	                        navType = iNavType.Value;


	                    // Set the navigateUrl to a specified one if no resource entries are given
	                    string urlValue;
	                    if(resourceUrl == null)
	                        urlValue = navigateUrl.Value;
	                    else
	                        urlValue = FormatUrl(resourceUrl.Value);

	                    // Create the CSLink and add it
	                    CSLink link = new CSLink(name.Value, (resourceName == null) ? null : resourceName.Value, (text == null) ? null : text.Value, urlValue, rolesValue, navType);
	                    _tabUrls.Add(link);
	                }
	            }
	        }
	    }

		#endregion

		#region Transformers
	    private static ListDictionary CreateTransformers(XmlNode transformers)
	    {
	        ListDictionary transforms = new ListDictionary();
	        foreach(XmlNode n in transformers.ChildNodes)
	        {
	            if(n.NodeType != XmlNodeType.Comment)
	            {
	                string k = n.Attributes["key"].Value;
	                string v = n.Attributes["value"].Value;

	                if(!Globals.IsNullorEmpty(k))
	                {
	                    transforms[k] = v;
	                }
	            }
	        }

            return transforms;
	    }
		#endregion

		#region Urls
	    private void CreateUrls(XmlNode urls, ListDictionary transforms)
	    {
	        foreach (XmlNode n in urls.ChildNodes) 
	        {

	            if (n.NodeType != XmlNodeType.Comment) 
	            {
                    string name = n.Attributes["name"].Value;


                    XmlAttribute direct = n.Attributes["navigateUrl"];
                    if(direct != null)
                    {
                       _paths.Add(name,direct.Value);
                    }
                    else
                    {

	                
                        string path = n.Attributes["path"].Value;

                        foreach(string key in transforms.Keys)
                        {
                            path = path.Replace(key,transforms[key].ToString());
                        }

                        string location = null;
                        XmlAttribute l = n.Attributes["location"];
                        if(l != null)
                            location = l.Value;

                        Location loc = _locationSet.FindLocationByName(location);

                        _paths.Add(name, loc.Path + path);

                        // Store the full path to avoid having key duplicates
                        //
                        string keyPath = loc.Path + path;
                        if (Globals.ApplicationPath.Length > 0)
                            keyPath = keyPath.Replace( Globals.ApplicationPath, "" ).ToLower();
                        _reversePaths.Add( keyPath, name );

                        XmlAttribute vanity = n.Attributes["vanity"];
                        XmlAttribute pattern = n.Attributes["pattern"];


                        //Store full paths like regular urls. 
                        if(vanity != null && pattern != null)
                        {


//                            string p = loc.Path + pattern.Value;
//                            string v = loc.PhysicalPath + vanity.Value;

                            string p = (!pattern.Value.StartsWith("/") ? loc.Path : String.Empty ) + pattern.Value;
                            string v = (!vanity.Value.StartsWith("/") ? loc.PhysicalPath : String.Empty) + vanity.Value;

                            foreach(string key in transforms.Keys)
                            {
                                p = p.Replace(key,transforms[key].ToString());
                                v = v.Replace(key,transforms[key].ToString());
                            }
                        
                            loc.Add(new ReWrittenUrl(location + "." + name,p,v));
                        }
                    }
                    
	            }

	        }
	    }

		#endregion

		#region LocationSet
	    private LocationSet CreateLocationSet(XmlNode basePaths, string globalPath)
	    {
            LocationSet ls = new LocationSet();
	        foreach(XmlNode n in basePaths.ChildNodes)
	        {
	            if(n.NodeType != XmlNodeType.Comment)
	            {
	                XmlAttribute name = n.Attributes["name"];
	                XmlAttribute path = n.Attributes["path"];
	                XmlAttribute physicalPath = n.Attributes["physicalPath"];
	                XmlAttribute exclude = n.Attributes["exclude"];
	                XmlAttribute ltype = n.Attributes["type"];

	                if(name != null && path != null)
	                {
	                    string pp = null;
	                    if(physicalPath != null)
	                    {
	                        pp = globalPath + physicalPath.Value;
	                    }

	                    bool isExeclude = (exclude != null && bool.Parse(exclude.Value));
	                    Location l = null;
	                    string vp = globalPath + path.Value;
	                    if(ltype == null)
	                    {
	                        l = new Location(vp, pp, isExeclude);
	                    }
	                    else
	                    {
	                        Type t = Type.GetType(ltype.Value);
	                        if(t == null)
	                        {
	                            CSException csEx = new CSException(CSExceptionType.UnknownError,"Type for custom location could not be loaded " + ltype.Value);
	                            csEx.Log();
	                            throw csEx;
	                        }

	                        l = Activator.CreateInstance(t,new object[]{vp,pp,isExeclude}) as Location;
	                        if(l == null)
	                        {
	                            CSException csEx = new CSException(CSExceptionType.UnknownError,"Type for custom location could not be loaded as an instance of Location" + ltype.Value);
	                            csEx.Log();
	                            throw csEx;
	                        }
	                    }
	                    ls.Add(name.Value,l);
	                }
	            }
	        }

            return ls;
	    }

		#endregion

	    public string FormatUrl(string name)
        {
            return FormatUrl(name,null);
        }

        public virtual string FormatUrl(string name, params object[] parameters)
        {
        	

            if(parameters == null)
                return this.Paths[name];

            else
                return string.Format(Paths[name],parameters);
        }

        #region Public Properties
        protected NameValueCollection _paths = null;
        protected NameValueCollection _reversePaths = null;
		protected ArrayList _tabUrls = null;
        protected string _locationFilter;
        protected LocationSet _locationSet = null;
		protected ArrayList _mappings = new ArrayList();


		public ArrayList Mappings
		{
			get { return _mappings;}
		}


        public LocationSet LocationSet
        {
            get { return _locationSet;}
        }

        public string LocationFilter
        {
            get
            {
                return _locationFilter;
            }
        }

        /// <summary>
        /// Property Paths (NameValueCollection)
        /// </summary>
        public NameValueCollection Paths
        {
            get {  return this._paths; }
        }



        /// <summary>
        /// Property Paths (NameValueCollection)
        /// </summary>
        public NameValueCollection ReversePaths
        {
            get {  return this._reversePaths; }
        }



		public ArrayList TabUrls
		{
			get
			{
				return _tabUrls;
			}
		}

        #endregion

        private static string ResolveUrl (string path) 
        {

            if (Globals.ApplicationPath.Length > 0)
                return Globals.ApplicationPath + path;
            else
                return path;
        }

	}
}
